import Vue from "vue";
import VueRouter from "vue-router";

// 页面
import Home from "../views/Home.vue";
import User from "../views/user/User.vue";
import Login from "../views/login/Login.vue";
import Reg from "../views/login/Reg.vue";
import Book from "../views/book/Book.vue";
import Lesson from "../views/lesson/Lesson.vue";

Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    name: "Home",
    //【命名视图】
		// 注意是components 加s
    components: {
      default: Home,
      a: Book,
      b: Lesson
    }
  },
  //【动态路由匹配】
  {
    //动态路由匹配，通过$route.params.user获取user的值
    //这样配置的话，/user/jack、/user/tom 都将匹配至 同一路由 User
    //如果从/user/jack 切换至 /user/tom 组件User并不会重新加载，也就是说，生命周期函数也不会重新运行
    //如果要对路由参数变化作出响应，建议使用【导航守卫】
    path: "/user/:user",
    name: "User",
    component: User,

    //【别名】
    // 只是URL不同，路由匹配依然是/user/wang
    // 访问/yonghu/wang 和/user/wang 没有任何区别
    alias: "/yonghu/:user",

    //【$route解耦】3个模式, 布尔模式，对象模式，函数模式
    // 布尔模式，route.params 将会被设置为组件属性
    props: true,

    //【路由私有的守卫】
    // beforeRouteEnter 进入前 用法和全局的导航守卫一样
    beforeEnter: (to, from, next) => {
      console.log("/user路由配置的 私有守卫beforeEnter");
      next();
    },
    // beforeRouteUpdate 更新前
    beforeRouteUpdate: (to, from, next) => {
      console.log("/user路由配置的 私有守卫beforeRouteUpdate");
      next();
    },
    beforeRouteLeave: (to, from, next) => {
      console.log("/user路由配置的 私有守卫beforeRouteLeave");
      next();
    },

    //【meta 路由元信息】
    meta: {
      //这里可以放任何信息
      //这里定义的meta是属于 /user 这个路由记录的
      //匹配到/user路由时，暴露的$route对象可以获取到meta
    },

    //【路由嵌套（子路由）】
    children: [
      {
        //路径为 /user/jack/login时 被匹配
        // Login会被渲染在 User的 <router-view>
        path: "login",
        component: Login
      },
      {
        path: "reg",
        component: Reg
      }
    ]
  },
  //【重定向】
  //将/home2的url被替换成 /，路由匹配为 /
  //重定向的路径 /home2 不会被导航守卫响应
  {
    path: "/home2",
    redirect: { path: "/" }
  },
  //【路由捕获】
  {
    //使用通配符 ‘*’ 来匹配所有路径，通常用于捕获404错误
    //例如：path: '/user-*' 可以匹配所有以/user-开头的路径
    //使用通配符的路径，尽可能的放在最后，匹配优先级按路由定义的顺序，越靠前的越高
    //会匹配所有路径
    path: "*"
    // component: 404页面组件
  }
];

const router = new VueRouter({
  routes
});

//【导航守卫】3种 全局的，router路由配置的私有的，组件内部的

// 【完整的导航解析流程】
// 导航被触发。
// 在失活的组件里调用 离开守卫。
// 调用全局的 beforeEach 守卫。
// 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
// 在路由配置里调用 beforeEnter。
// 解析异步路由组件。
// 在被激活的组件里调用 beforeRouteEnter。
// 调用全局的 beforeResolve 守卫 (2.5+)。
// 导航被确认。
// 调用全局的 afterEach 钩子。
// 触发 DOM 更新。
// 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。

//【全局的导航守卫】  “导航”表示路由正在发生改变。
//【beforeEach】 router注册的一个 全局的 前置守卫。
//钩子的时间点在 导航发生之前
//to: Route，即将要进入的目标 路由对象
//from: Route，当前导航正要离开的路由对象
//next: Function，一定要调用这个方法，来resolve这个钩子。执行效果依赖 next方法的调用参数
router.beforeEach((to, from, next) => {
  console.log("全局前置守卫to.path：", to.path);
  console.log("全局前置守卫from.path：", from.path);

  //next方法，必须被调用。
  //next() 进行管道中的下一个钩子。如果全部钩子执行完了，则导航的状态就是 confirmed (确认的)。
  next();

  //next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断，然后进行一个新的导航。
  //可以向 next 传递任意位置对象，且允许设置诸如 name: 'home' 之类的选项以及任何用在 router-link的to、 prop 或 router.push 中的选项。

  // next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例，则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
});

//【beforeResolve】 全局的解析守卫
// 它和beforeEach类似，区别是，beforeResolve是 在导航被确认之前 同时在所有组件内守卫和异步路由组件被解析之后 解析守卫就被调用
// router.beforeResolve((to, from, next)=>{})

//【afterEach】全局 后置钩子，执行在导航被确认之后
//只接收 to ， from， 2个参数
//这个钩子不会接收next函数，它也不会改变导航本身。
// router.afterEach((to, from)=>{})

export default router;
